package pipeline.fragment;

import javax.vecmath.Color3f;
import javax.vecmath.Vector3f;

import pipeline.Pipeline;
import pipeline.PointLight;
import pipeline.misc.Fragment;
import pipeline.misc.FrameBuffer;

/**
 * This is the fragment program which actually uses a shading model to compute
 * the color on a per fragment basis.
 * 
 * @author ags
 */
public class PhongShadedFP extends FragmentProcessor
{
        Vector3f E = new Vector3f();
        Vector3f L = new Vector3f();
        Vector3f N = new Vector3f();
        Vector3f H = new Vector3f();
        Vector3f V = new Vector3f();
        Color3f c = new Color3f();
        Color3f c2 = new Color3f();
        
        
        public int nAttr()
        {
                return 9;
        }
        
        protected Color3f colorForFragment(Fragment frag)
        {
                V.set(frag.attrs[4], frag.attrs[5], frag.attrs[6]);                
                E.set(-V.x, -V.y, -V.z);
                E.normalize();
                N.set(frag.attrs[7], frag.attrs[8], frag.attrs[9]);
                N.normalize();
                c.set(frag.attrs[1], frag.attrs[2], frag.attrs[3]);                                
                c2.set(Pipeline.ambientIntensity*c.x, Pipeline.ambientIntensity*c.y, Pipeline.ambientIntensity*c.z);
                
                for(PointLight light : Pipeline.lights) {
                        Color3f lc = light.getIntensity();

                        L.set(light.getPosition());
                        L.sub(V);
                        L.normalize();
                        
                        float dot = L.dot(N);

                        if(dot > 0) {
                                c2.x += c.x*dot*lc.x;
                                c2.y += c.y*dot*lc.y;
                                c2.z += c.z*dot*lc.z;
                        }                        
                        H.set(L);
                        H.add(E);
                        H.normalize();                        
                        dot = H.dot(N);                       
                        // Specular highlights
                        if(dot > 0) {
                                dot = (float) Math.pow(dot, Pipeline.specularExponent);
                                
                                c2.x += dot*Pipeline.specularColor.x;
                                c2.y += dot*Pipeline.specularColor.y;
                                c2.z += dot*Pipeline.specularColor.z;
                        }
                }              
                // Clamp
                if(c2.x > 1) {
                        c2.x = 1;
                }
                if(c2.y > 1) {
                        c2.y = 1;
                }
                if(c2.z > 1) {
                        c2.z = 1;
                }
                return c2;
        }

        public void fragment(Fragment f, FrameBuffer fb)
        {
                float z = f.attrs[0];
                if(z >= fb.getZ(f.x, f.y)) {
                    return;
                }
                Color3f c = colorForFragment(f);                
                fb.set(f.x, f.y, c.x, c.y, c.z, z);
        }
}

